/*
 * Copyright (c) 2018.
 * http://www.ulabcare.com
 */

package com.mt.roll.upms.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mt.roll.core.base.BaseService;
import com.mt.roll.core.dal.entity.SysOrg;
import com.mt.roll.core.dal.entity.SysUser;
import com.mt.roll.core.dal.entity.SysUserRole;
import com.mt.roll.core.dal.service.SysOrgServiceBiz;
import com.mt.roll.core.dal.service.SysUserRoleServiceBiz;
import com.mt.roll.core.dal.service.SysUserServiceBiz;
import com.mt.roll.core.enums.WhetherEnum;
import com.mt.roll.core.errorcode.ApiErrorCode;
import com.mt.roll.core.params.EnabledParam;
import com.mt.roll.core.params.IdListParam;
import com.mt.roll.core.params.IdParam;
import com.mt.roll.core.utils.PasswordUtil;
import com.mt.roll.core.vo.IdListVo;
import com.mt.roll.core.vo.IdVo;
import com.mt.roll.core.vo.R;
import com.mt.roll.upms.mapper.UserMapper;
import com.mt.roll.upms.params.*;
import com.mt.roll.upms.service.UserService;
import com.mt.roll.upms.vo.SysUserVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 用户服务实现类
 *
 * @author jiff
 * @date 2018/11/14
 * @since 1.0
 */
@Slf4j
@Service("upmsUserService")
@Transactional
public class UserServiceImpl extends BaseService implements UserService {
    @Autowired
    private SysUserServiceBiz sysUserServiceBiz;
    @Autowired
    private SysOrgServiceBiz sysOrgServiceBiz;

    @Autowired
    private SysUserRoleServiceBiz sysUserRoleServiceBiz;

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private MessageSource messageSource;


    /**
     * 获取用户
     *
     * @param idParam 主键参数
     * @return 用户
     */
    @Override
    public R<SysUserVo> get(IdParam idParam) {
        SysUser sysUser = sysUserServiceBiz.getById(idParam.getId());
        if (sysUser == null) {
            return failed(ApiErrorCode.USER_NON_EXISTENT);
        }
        if (!hasPermission(sysUser)) {
            return failed(ApiErrorCode.FORBIDDEN_DATA);
        }
        SysUserVo sysUserVo = SysUserVo.builder().build();
        BeanUtils.copyProperties(sysUser, sysUserVo);

        SysOrg org = sysOrgServiceBiz.getById(sysUser.getOrgId());
        if (org != null) {
            sysUserVo.setOrgName(org.getName());
        }
        return successful(sysUserVo);
    }

    /**
     * 获取用户列表
     *
     * @param sysUserQueryParam 用户查询参数
     * @return 用户列表
     */
    @Override
    public R<List<SysUserVo>> list(SysUserQueryParam sysUserQueryParam) {
        SysOrg org = null;
        if (sysUserQueryParam.getOrgId() != null) {
            org = sysOrgServiceBiz.getById(sysUserQueryParam.getOrgId());
            if (!hasPermission(org)) {
                return failed(ApiErrorCode.FORBIDDEN_DATA);
            }
        }
        //未指定组织使用当前登录用户所在组织
        if (org == null) {
            org = sysOrgServiceBiz.getById(getLoginUser().getOrgId());
        }
        //未限定只查询当前组织用户则使用家谱ID查询
        if (sysUserQueryParam.getOrgScope() == null || sysUserQueryParam.getOrgScope().equals(WhetherEnum.NO.getValue())) {
            sysUserQueryParam.setGenealogyId(org.getGenealogyId());
            sysUserQueryParam.setOrgId(null);
        } else {
            sysUserQueryParam.setOrgId(org.getId());
        }
        List<SysUserVo> sysUserVos = userMapper.listByOrg(sysUserQueryParam);
        return successful(sysUserVos);
    }

    /**
     * 获取用户分页列表
     *
     * @param sysUserQueryParam 用户查询参数
     * @return 用户分页列表
     */
    @Override
    public R<IPage<SysUserVo>> page(SysUserQueryParam sysUserQueryParam) {
        SysOrg org = null;
        if (sysUserQueryParam.getOrgId() != null) {
            org = sysOrgServiceBiz.getById(sysUserQueryParam.getOrgId());
            if (!hasPermission(org)) {
                return failed(ApiErrorCode.FORBIDDEN_DATA);
            }
        }
        //未指定组织使用当前登录用户所在组织
        if (org == null) {
            org = sysOrgServiceBiz.getById(getLoginUser().getOrgId());
        }
        //未限定只查询当前组织用户则使用家谱ID查询
        if (sysUserQueryParam.getOrgScope() == null || sysUserQueryParam.getOrgScope().equals(WhetherEnum.NO.getValue())) {
            sysUserQueryParam.setGenealogyId(org.getGenealogyId());
            sysUserQueryParam.setOrgId(null);
        } else {
            sysUserQueryParam.setOrgId(org.getId());
        }
        IPage<SysUserVo> page = new Page<>(sysUserQueryParam.getCurrent(), sysUserQueryParam.getSize());
        List<SysUserVo> sysUserVos = userMapper.listByOrg(page, sysUserQueryParam);
        page.setRecords(sysUserVos);
        return successful(page);
    }

    /**
     * 新增用户
     *
     * @param sysUserParam 用户参数
     * @return 主键
     */
    @Override
    public R<IdVo> add(SysUserParam sysUserParam) {
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.eq(SysUser.MOBILE, sysUserParam.getMobile());
        SysUser sysUser = sysUserServiceBiz.getOne(wrapper);
        if (sysUser != null) {
            return failed(ApiErrorCode.USER_EXISTENT);
        }
        SysOrg sysOrg = sysOrgServiceBiz.getById(sysUserParam.getOrgId());
        if (sysOrg == null) {
            return failed("组织不存在");
        }

        //创建系统用户
        sysUser = new SysUser();
        BeanUtils.copyProperties(sysUserParam, sysUser);
        sysUser.setAccount(sysUser.getMobile());
        String nonceStr = PasswordUtil.genNonce();
        String encodePassword = PasswordUtil.encode(sysUser.getPassword(), nonceStr);
        sysUser.setPassword(encodePassword);
        sysUser.setNonceStr(nonceStr);

        setCommonField(sysUser);
        sysUserServiceBiz.save(sysUser);

        return successful(IdVo.builder().id(sysUser.getId()).build());
    }

    /**
     * 更新用户
     *
     * @param sysUserParam 用户参数
     * @return 主键
     */
    @Override
    public R<IdVo> update(SysUserParam sysUserParam) {
        SysUser sysUser = sysUserServiceBiz.getById(sysUserParam.getId());
        if (sysUser == null) {
            return failed(ApiErrorCode.USER_NON_EXISTENT);
        }
        SysOrg sysOrg = sysOrgServiceBiz.getById(sysUserParam.getOrgId());
        if (sysOrg == null) {
            return failed("组织不存在");
        }
        if (!hasPermission(sysUser)) {
            return failed(ApiErrorCode.FORBIDDEN_DATA);
        }
        SysUser updateSysUser = new SysUser().setId(sysUser.getId());
        BeanUtils.copyProperties(sysUserParam, updateSysUser, "mobile", "password");
        setUpdateCommonField(updateSysUser);
        sysUserServiceBiz.updateById(updateSysUser);
        return successful(IdVo.builder().id(sysUser.getId()).build());
    }

    /**
     * 启用停用
     *
     * @param enabledParam 启停参数
     * @return 主键
     */
    @Override
    public R<IdVo> enabled(EnabledParam enabledParam) {
        SysUser sysUser = sysUserServiceBiz.getById(enabledParam.getId());
        if (sysUser == null) {
            return failed(ApiErrorCode.USER_NON_EXISTENT);
        }
        if (!hasPermission(sysUser)) {
            return failed(ApiErrorCode.FORBIDDEN_DATA);
        }
        if (!enabledParam.getEnabled().equals(sysUser.getEnabled())) {
            SysUser updateSysUser = new SysUser().setId(sysUser.getId());
            updateSysUser.setEnabled(enabledParam.getEnabled());
            setUpdateCommonField(updateSysUser);
            sysUserServiceBiz.updateById(updateSysUser);
        }
        return successful(IdVo.builder().id(sysUser.getId()).build());
    }


    /**
     * 修改密码
     *
     * @param modifyPasswordParam 修改密码参数
     * @return 主键
     */
    @Override
    public R<IdVo> modifyPassword(ModifyPasswordParam modifyPasswordParam) {
        SysUser sysUser = sysUserServiceBiz.getById(getLoginUser().getUserId());
        if (sysUser == null) {
            return failed(ApiErrorCode.USER_NON_EXISTENT);
        }
        if (!sysUser.getPassword().equals(PasswordUtil.encode(modifyPasswordParam.getPassword(), sysUser.getNonceStr()))) {
            return failed("原密码错误");
        }

        SysUser updateSysUser = new SysUser().setId(sysUser.getId());
        String nonceStr = PasswordUtil.genNonce();
        String encodePassword = PasswordUtil.encode(modifyPasswordParam.getNewPassword(), nonceStr);
        updateSysUser.setPassword(encodePassword);
        updateSysUser.setNonceStr(nonceStr);
        setUpdateCommonField(updateSysUser);
        sysUserServiceBiz.updateById(updateSysUser);
        return successful(IdVo.builder().id(sysUser.getId()).build());
    }

    /**
     * 重置密码
     *
     * @param resetPasswordParam 重新密码参数
     * @return 主键
     */
    @Override
    public R<IdVo> resetPassword(ResetPasswordParam resetPasswordParam) {
        SysUser sysUser = sysUserServiceBiz.getById(resetPasswordParam.getId());
        if (sysUser == null) {
            return failed(ApiErrorCode.USER_NON_EXISTENT);
        }
        if (!hasPermission(sysUser)) {
            return failed(ApiErrorCode.FORBIDDEN_DATA);
        }
        SysUser updateSysUser = new SysUser().setId(sysUser.getId());
        String nonceStr = PasswordUtil.genNonce();
        String encodePassword = PasswordUtil.encode(resetPasswordParam.getPassword(), nonceStr);
        updateSysUser.setPassword(encodePassword);
        updateSysUser.setNonceStr(nonceStr);
        setUpdateCommonField(updateSysUser);
        sysUserServiceBiz.updateById(updateSysUser);
        return successful(IdVo.builder().id(sysUser.getId()).build());
    }

    /**
     * 找回密码
     *
     * @param findPasswordParam 找回密码参数
     * @return 主键
     */
    @Override
    public R<IdVo> findPassword(FindPasswordParam findPasswordParam) {
        return null;
    }


    /**
     * 删除用户
     *
     * @param idParam 主键参数
     * @return 主键
     */
    @Override
    public R<IdVo> delete(IdParam idParam) {
        SysUser sysUser = sysUserServiceBiz.getById(idParam.getId());
        if (sysUser == null) {
            return failed(ApiErrorCode.USER_NON_EXISTENT);
        }
        if (!hasPermission(sysUser)) {
            return failed(ApiErrorCode.FORBIDDEN_DATA);
        }
        //删除用户角色关系
        sysUserRoleServiceBiz.remove(new QueryWrapper<SysUserRole>().eq(SysUserRole.USER_ID, sysUser.getId()));
        //使用更新方式删除，需要把mobile设置为历史mobile（后面跟随机数）
        SysUser updateSysUser = new SysUser().setId(sysUser.getId());
        updateSysUser.setMobile(sysUser.getMobile() + "_" + RandomUtils.nextInt());
        updateSysUser.setValid(WhetherEnum.NO.getValue());
        setUpdateCommonField(updateSysUser);
        sysUserServiceBiz.updateById(updateSysUser);
        //更新时逻辑删除字段没有更新，需要再调用一次删除操作
        sysUserServiceBiz.removeById(idParam.getId());
        return successful(IdVo.builder().id(sysUser.getId()).build());
    }

    /**
     * 批量删除用户
     *
     * @param idListParam 主键列表参数
     * @return 主键列表
     */
    @Override
    public R<IdListVo> delete(IdListParam idListParam) {
        Collection<SysUser> sysUsers = sysUserServiceBiz.listByIds(idListParam.getIds());
        if (CollectionUtils.isEmpty(sysUsers)) {
            return failed(ApiErrorCode.USER_NON_EXISTENT);
        }
        for (SysUser sysUser : sysUsers) {
            if (!hasPermission(sysUser)) {
                return failed(ApiErrorCode.FORBIDDEN_DATA);
            }
        }
        List<SysUser> updateSysUsers = new ArrayList<>(sysUsers.size());
        for (SysUser sysUser : sysUsers) {
            //删除用户角色关系
            sysUserRoleServiceBiz.remove(new QueryWrapper<SysUserRole>().eq(SysUserRole.USER_ID, sysUser.getId()));
            //使用更新方式删除，需要把mobile设置为历史mobile（后面跟随机数）
            SysUser updateSysUser = new SysUser().setId(sysUser.getId());
            updateSysUser.setMobile(sysUser.getMobile() + "_" + RandomUtils.nextInt());
            updateSysUser.setValid(WhetherEnum.NO.getValue());
            setUpdateCommonField(updateSysUser);
            updateSysUsers.add(updateSysUser);
        }
        sysUserServiceBiz.updateBatchById(updateSysUsers);
        //更新时逻辑删除字段没有更新，需要再调用一次删除操作
        sysUserServiceBiz.removeByIds(idListParam.getIds());
        return successful(IdListVo.builder().ids(idListParam.getIds()).build());
    }


    /**
     * 判断登录用户是否有修改该用户的权限，主要基于登录用户和被修改用户是否归属同一组织或上下级组织关系
     *
     * @param sysUser 被修改的用户
     * @return true允许修改，否则不允许
     */
    private boolean hasPermission(SysUser sysUser) {
        if (sysUser.getOrgId() == null) {
            return false;
        }
        SysOrg sysOrg = sysOrgServiceBiz.getById(sysUser.getOrgId());
        if (sysOrg == null) {
            return false;
        }
        return hasPermission(sysOrg);
    }

    /**
     * 判断登录用户是否有修改该组织的权限，主要基于登录用户和被修改组织是否归属同一组织或上下级组织关系
     *
     * @param sysOrg 被修改的用户
     * @return true允许修改，否则不允许
     */
    private boolean hasPermission(SysOrg sysOrg) {
        if (sysOrg == null) {
            return false;
        }
        Long loginOrgId = getLoginUser().getOrgId();
        if (loginOrgId == null) {
            return false;
        }
        SysOrg loginSysOrg = sysOrgServiceBiz.getById(loginOrgId);
        if (loginSysOrg == null) {
            return false;
        }
        if (StringUtils.isAnyBlank(sysOrg.getGenealogyId(), loginSysOrg.getGenealogyId())) {
            return false;
        }
        return sysOrg.getGenealogyId().startsWith(loginSysOrg.getGenealogyId());
    }

}
